/**
 * 基类Action
 */
interface Action {
    type: string;
}

/**
 * 删除消息的action
 */
interface DeleteMessageAction extends Action {
    index: number;
}

/**
 * 添加消息的action
 */
interface AddMessageAction extends Action {
    message: string;
}

interface Reducer<T> {
    (state: T, action: Action): T;
}

/**
 * 监听函数/订阅函数
 */
interface ListenerCallback {
    (): void
}

/**
 * 退订函数
 */
interface UnsubscribeCallback {
    (): void;
}

class Store<T> {
    private _messages: T;
    private _listeners: Array<ListenerCallback> = new Array<ListenerCallback>();
    constructor(private reducer: Reducer<T>, initMessage: T) {
        this._messages = initMessage;
    }

    getState(): T {
        return this._messages;
    };

    subscribe(listener: ListenerCallback): UnsubscribeCallback {
        this._listeners.push(listener);
        return () => {
            this._listeners = this._listeners
                .filter((currentListener: ListenerCallback) => listener !== currentListener);
        }
    }

    dispatch(action: Action) {
        this._messages = this.reducer(this._messages, action);
        this._listeners.forEach((listener: ListenerCallback) => {
            listener();
        });
    }
}

const DELETE_MESSAGE = 'DELETE_MESSAGE';
const ADD_MESSAGE = 'ADD_MESSAGE';
const reducer: Reducer<Array<string>> = (state: Array<string>, action: Action) => {
    switch (action.type) {
        case DELETE_MESSAGE:
            return [...state.slice(0, (action as DeleteMessageAction).index)
                , ...state.slice((action as DeleteMessageAction).index + 1, state.length - 1)];
        case ADD_MESSAGE:
            return [...state, (action as AddMessageAction).message];
        default:
            return state;

    }
}
const store: Store<Array<string>> = new Store(reducer, ['Listen! This is a dialog!']);
store.subscribe(() => {
    store.getState().forEach((message: string) => {
        console.log(message + '\n');
    });
});
store.dispatch({type: ADD_MESSAGE, message: 'Jerry: How are you?'} as Action);
store.dispatch({type:ADD_MESSAGE, message: 'Tom: I\'m fine, and you?'} as Action);
store.dispatch({type: ADD_MESSAGE, message: 'Jerry: I\'m fine too, thanks!'} as Action);